//这个程序表达了cuSPARSE库来进行相同图染色的效果
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<cusparse.h>

//用来计时的函数
#include<sys/time.h>

int main(){
    //存列索引的数组
    int* A_col;

    //存行索引的数组
    int* A_row;

    //矩阵A的行数
    int A_size = 32768;

    //为每个指针创造27个空间
    //遍历变量
    printf("申请空间\n");

    //A_col的空间申请，一口气先申请4096*27的空间
    cudaMallocHost((void **)&A_col, A_size * 27 * sizeof(int));

    cudaMallocHost((void **)&A_row, sizeof(int) * (A_size + 1));
    
    //非0元的数量
    int A_nz = 0;
    
    //从文件中读入数据
    FILE* Graph_File;

    //打开文件
    Graph_File = fopen("../data/A_Matrix_col_1.txt", "r");

    //用一个缓冲区来获取读取的内容
    char read_line_buf[1024];

    //用一个变量来遍历A的每一行
    int A_row_index = 0;

    printf("读取文件\n");

    fgets(read_line_buf, 1024, Graph_File);

    while (!feof(Graph_File)) {
        //更新A_row
        A_row[A_row_index] = A_nz;
        
        //分割字符串，这里是每一个子串
        char* part_char;

        part_char = strtok(read_line_buf, " ");

        while(part_char != NULL){
            //更新A_col
            A_col[A_nz] = atoi(part_char);

            A_nz++;

            part_char = strtok(NULL, " ");
        }

        //先读，才能查到eof
        fgets(read_line_buf, 1024, Graph_File);

        A_row_index++;
    }

    //最后更新一次A_row
    A_row[A_size] = A_nz;

    fclose(Graph_File);

    //打印A_row
    // int i;
    // for(i = 0 ; i < A_size+1; i++){
    //     printf("%d ", A_row[i]);
    // }

    // printf("\n");

    //调用cuSPARSE图染色
    //创造句柄
    cusparseHandle_t handle;
    cusparseCreate(&handle);

    //将row，val，col索引放到显存上
    int* A_row_device = 0;
    cudaMalloc((void **)&A_row_device, sizeof(int) * (A_size + 1));
    cudaMemcpy(A_row_device, A_row, sizeof(int) * (A_size + 1), cudaMemcpyHostToDevice);
    int* A_col_device = 0;
    cudaMalloc((void **)&A_col_device, sizeof(int) * A_nz);
    cudaMemcpy(A_col_device, A_col, sizeof(int) * A_nz, cudaMemcpyHostToDevice);
    float* A_val_device = 0;
    cudaMalloc((void **)&A_val_device, sizeof(float) * A_nz);

    //我们在gpu上申请数组
    int *coloring_device;
    cudaMalloc((void **)&coloring_device , A_size * sizeof(int));
    cudaMemset(coloring_device, 0, A_size * sizeof(int));

    //申请reordering，我们现在还不知道这个能够得到什么，我们按照点的数量来给他申请空间
    int *reordering_device;
    cudaMalloc((void **)&reordering_device , A_size * sizeof(int));
    cudaMemset(reordering_device, 0, A_size * sizeof(int));

    //这个是需要严谨染色的节点染色的比例，我们设定为1，让所有的节点全部接受严谨染色
    float fractionToColor = 1;
    //颜色的数量
    int ncolors = 0;
    //上面这两个变量都是单个变量，不用在显存上申请空间，并且来回传输就可以通过指针直接修改

    //初始化矩阵的描述信息，cusparseMatDescr_t这个结构体通常保存了矩阵的索引标准和矩阵类型等信息。
    cusparseMatDescr_t descr;
    cusparseCreateMatDescr(&descr);

    //设定为普通矩阵，从0开始索引
    cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL);
    cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO);

    cusparseColorInfo_t info;
    cusparseCreateColorInfo(&info);
    
    //计时开始
    struct timeval starttime,endtime;
    
    double timeuse;

    gettimeofday(&starttime,NULL);

    cusparseScsrcolor(handle, A_size, A_nz, descr, A_val_device, A_row_device, A_col_device, &fractionToColor, 
        &ncolors, coloring_device, reordering_device, info);
    
    //计时结束
    gettimeofday(&endtime,NULL);

    timeuse=(1000000*(endtime.tv_sec-starttime.tv_sec)+endtime.tv_usec-starttime.tv_usec)/1000;
    
    printf("颜色数量:%d\n", ncolors);
    printf("使用的时间:%fms\n", timeuse);


    //析构A数组
    cudaFreeHost(A_col);

    cudaFreeHost(A_row);

    cudaFree(A_row_device);

    cudaFree(A_col_device);

    cudaFree(A_col_device);

    cudaFree(coloring_device);

    cudaFree(reordering_device);

}